﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevComponents.DotNetBar;
using ESRI.ArcGIS.Controls;
using com.zjgis.arcengineutility;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Geodatabase;
using System.IO;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.DataSourcesFile;
using ZJGIS.DataConvert.model.DataTransformation;
using System.Collections;

namespace ZJGIS.DataConvert.form
{
    /// <summary>
    /// 坐标装换工具
    /// 需要54和80的图幅结合表数据
    /// add by wzy
    /// </summary>
    public partial class FrmDataTransformation : Form
    {
        private AxMapControl MapControl;
        private string m_strTufuNumField;

        const string sTF54 = "图廓54";
        const string sTF80 = "图廓80";

        //实现窗体的单态，每次弹出的窗口都为同一个
        private static FrmDataTransformation DataTransformationForm;

        public AxMapControl MapControlOutProp
        {
            get { return MapControl; }
            set { MapControl = value; }
        }

        public FrmDataTransformation()
        {
            InitializeComponent();
        }

        public static FrmDataTransformation GetDataTransformationForm()
        {
            if (DataTransformationForm == null)
            {
                DataTransformationForm = new FrmDataTransformation();
            }

            return DataTransformationForm;
        }

        private void FrmDataTramfomation_Load(object sender, EventArgs e)
        {
            IMap pMap = MapControl.Map ;
            List<IFeatureLayer> lstFLs = CartoUtility.GetAllFeaturelayersFromMap(pMap);
            foreach (IFeatureLayer pFL in lstFLs)
            {
                if (pFL.Valid == true)
                {
                    this.checkedListBox1.Items.Add(pFL.Name);
                }
            }
            cboType.SelectedIndex = 0;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            IFeatureClass pFeatureClassF = null;
            IFeatureClass pFeatureClassT = null;

            if (this.radioButton1.Checked == true)
            {
                pFeatureClassF = GetIDXFeatCls(sTF54);
                pFeatureClassT = GetIDXFeatCls(sTF80);
            }
            else
            {
                pFeatureClassF = GetIDXFeatCls(sTF80);
                pFeatureClassT = GetIDXFeatCls(sTF54);
            }

            if (pFeatureClassF == null || pFeatureClassT == null)
            {
                return;
            }

            ISpatialReference pSpatialReferenceF = DataTransformation.getSpatialReference(pFeatureClassF);
            ISpatialReference pSpatialReferenceT = DataTransformation.getSpatialReference(pFeatureClassT);

            m_strTufuNumField = com.zjgis.cfgis.config.SystemConfig.systemConfigXml.基本信息.图号字段;
            if (pFeatureClassF.FindField(m_strTufuNumField) < 0 || 
                pFeatureClassF.FindField(m_strTufuNumField) < 0)
            {
                logPanel1.ErrLog("图号字段配置错误！");
                return;
            }

            int iFLCount = this.checkedListBox1.CheckedItems.Count;
            if (iFLCount == 0)
            {
                logPanel1.ErrLog("请选择需要进行坐标转换的图层");
                return;
            }

            if (txtExportPath.ControlText == "")
            {
                logPanel1.ErrLog("目标数据路径为空，请设置目标数据路径");
                return;
            }

            //构建坐标转换关系
            logPanel1.Log("正在构建坐标转换关系");
            List<TuFu> lstTFAll = DataTransformation.GetTufusAll(pFeatureClassF, m_strTufuNumField);
            if (lstTFAll == null)
            {
                logPanel1.ErrLog("原始坐标系结合图数据为空,构建转换关系失败!");
                return;
            }

            IPointCollection FromPtCollAll = DataTransformation.getControlPoints(lstTFAll, pFeatureClassF, m_strTufuNumField);
            IPointCollection ToPtCollAll = DataTransformation.getControlPoints(lstTFAll, pFeatureClassT, m_strTufuNumField);

            ITransformation pTransformation = DataTransformation.getTransformation(FromPtCollAll, ToPtCollAll);
            if (pTransformation == null)
            {
                logPanel1.ErrLog("构建转换关系失败!");
                return;
            }
            logPanel1.DoneLog("构建坐标转换关系成功");

            progressBar2.Maximum = iFLCount;
            progressBar2.Value = 0;

            //判断导出数据的类型
            zjgisWorkspaceType workspaceType;
            switch (cboType.SelectedIndex)
            {
                case 0:
                    workspaceType = zjgisWorkspaceType.gdb;
                    break;

                case 1:
                    workspaceType = zjgisWorkspaceType.mdb;
                    break;

                case 2:
                    workspaceType = zjgisWorkspaceType.shp;
                    break;
                default:
                    return;
            }

            //创建库体
            logPanel1.Log("正在创建坐标转换目标库体");
            IWorkspace pTargetWs = DataTransformation.GetTargetWorkspace(txtExportPath.ControlText, workspaceType, logPanel1);
            logPanel1.DoneLog("创建坐标转换目标库体成功");
            if (pTargetWs == null) return;

            logPanel1.Log("开始执行坐标转换处理");

            foreach (object itemChecked in checkedListBox1.CheckedItems)
            {
                string sFName = itemChecked.ToString();
                IFeatureLayer pFeatureLayer = CartoUtility.FindFeatureLayerByName(MapControl.Map, sFName);
                IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;

                logPanel1.Log("正在处理要素类" + sFName);

                ISpatialReference pSpatialReference = DataTransformation.getSpatialReference(pFeatureClass);

                //if (pSpatialReference.Equals(pSpatialReferenceF) == false)
                if (pSpatialReference.FactoryCode != pSpatialReferenceF.FactoryCode)
                {
                    logPanel1.ErrLog("图层" + sFName + "投影与源坐标系不符合,不能转换该图层");
                    progressBar2.Value = progressBar2.Value + 1;
                    continue;
                }

                IFeatureClass pFeatClsTarget =null ;
                Hashtable fieldRelation =null ;

                IDataset pDataset = pFeatureClass as IDataset;
                bool bCreated = DataTransformation.CreateFeatCls(pFeatureClass, pDataset.Name, ref pFeatClsTarget, ref fieldRelation, pTargetWs, pSpatialReferenceT, logPanel1);

                if (bCreated == false)
                {
                    progressBar2.Value = progressBar2.Value + 1;
                    continue;
                }

                DataTransformation.TransformFeatureClass(pFeatureClass, pFeatClsTarget, pTransformation, fieldRelation, progressBar1, logPanel1);

                progressBar2.Value = progressBar2.Value + 1;
            }
            logPanel1.DoneLog("坐标转换处理完成");
            MapControl.Refresh();
        }

        /// <summary>
        /// 图层坐标装换
        /// </summary>
        /// <param name="pFeatureClass">待装换的要素类</param>
        /// <param name="pFeatureClassF">源坐标系图幅结合表要素类</param>
        /// <param name="pFeatureClassT">目标坐标系图幅结合表要素类</param>
        private void TransformFeatureClass(IFeatureClass pFeatureClass, IFeatureClass pFeatureClassF, IFeatureClass pFeatureClassT)
        {
            int iCount = pFeatureClass.FeatureCount(null);
            this.progressBar1.Maximum = iCount;
            this.progressBar1.Value = 0;
            int iCountSuccess = 0;
            int iCountErr = 0;

            logPanel1.Log("正在对图层" + pFeatureClass.AliasName + "进行坐标转换处理");

            IFeatureCursor pFeatureCursor = pFeatureClass.Search(null, false);

            IFeature pFeature = pFeatureCursor.NextFeature();
            while (pFeature != null)
            {
                IGeometry pGeometry = pFeature.Shape;

                List<TuFu> lstTF = GetTufusByGeom(pGeometry, pFeatureClassF);
                if (lstTF == null)
                {
                    logPanel1.ErrLog("要素" + pFeature.OID + "超出控制范围，转换失败");
                    iCountErr = iCountErr + 1;
                    progressBar1.Value = progressBar1.Value + 1;
                    pFeature = pFeatureCursor.NextFeature();
                    continue;
                }

                IPointCollection FromPtColl = getControlPoints(lstTF, pFeatureClassF);
                IPointCollection ToPtColl = getControlPoints(lstTF, pFeatureClassT);

                bool bSuccess = TransformGeo(FromPtColl, ToPtColl, pGeometry);

                if (bSuccess == true)
                {
                    pFeature.Store();
                    iCountSuccess = iCountSuccess + 1;
                }
                else
                {
                    logPanel1.ErrLog("要素" + pFeature.OID + "没有匹配合法的控制点，转换失败");
                    iCountErr = iCountErr + 1;
                }

                this.progressBar1.Value = progressBar1.Value + 1;
                pFeature = pFeatureCursor.NextFeature();
            }

            logPanel1.Log("图层" + pFeatureClass.AliasName + "坐标转换处理完成，共" + iCount + "个要素，转换成功" + iCountSuccess + "个，失败" + iCountErr + "个。");
        }

        /// <summary>
        /// 根据图幅列表获取控制点集
        /// 使用图幅角点作为控制点
        /// 不考虑图幅的点序问题，因此要求所有图幅结合表要素类都是使用相同的工具生成
        /// 如考虑点序问题，需要再对点的坐标位置进行比较判断，效率会较低
        /// </summary>
        /// <param name="lstTF">图幅列表</param>
        /// <param name="pFeatureClass">图幅结合表要素类</param>
        /// <returns>控制点列表</returns>
        private IPointCollection getControlPoints(List<TuFu> lstTF, IFeatureClass pFeatureClass)
        {
            IPointCollection pPCAll = new MultipointClass();
            object Missing = Type.Missing;
            foreach (TuFu tf in lstTF)
            {
                IQueryFilter queryFilter = new QueryFilterClass();
                queryFilter.WhereClause = m_strTufuNumField + "= '" + tf.TuFuName + "'";
                IFeatureCursor pFeatureCursor = pFeatureClass.Search(queryFilter, false);
                IFeature pFeature = pFeatureCursor.NextFeature();
                if (pFeature != null)
                {
                    IPolygon pPolygon = pFeature.Shape as IPolygon;
                    IPointCollection pPCSub = pPolygon as IPointCollection;
                    for (int i = 0; i < pPCSub.PointCount; i++)
                    {
                        IPoint pPoint = pPCSub.get_Point(i);
                        if (isContained(pPoint, pPCAll) == false)
                        {
                            pPCAll.AddPoint(pPoint, ref Missing, ref Missing);
                        }
                    }
                }
            }
            return pPCAll;
        }

        /// <summary>
        /// 判断点是否已被点集所包含
        /// </summary>
        /// <param name="pPoint">点</param>
        /// <param name="pPC">点集</param>
        /// <returns>包含关系</returns>
        private bool isContained(IPoint pPoint, IPointCollection pPC)
        {
            IRelationalOperator pRO = pPoint as IRelationalOperator;
            for (int i = 0; i < pPC.PointCount; i++)
            {
                if (pRO.Equals(pPC.get_Point(i)))
                {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 坐标装换（二次多项式法AffineTransformation2D）
        /// </summary>
        /// <param name="FromPtColl">源控制点点集</param>
        /// <param name="ToPtColl">目标控制点点集</param>
        /// <param name="pGeo">待转换的图形</param>
        /// <returns>是否转换成功</returns>
        private bool TransformGeo(IPointCollection FromPtColl, IPointCollection ToPtColl, IGeometry pGeo)
        {
            try
            {
                //判断给定的控制点是否合法
                if (FromPtColl.PointCount != ToPtColl.PointCount)
                {
                    //控制点不成对错误
                    return false;
                }
                if (FromPtColl.PointCount < 4)
                {
                    //控制点不能少于4个 
                    return false;
                }

                //定义控制点数组
                int ControlPtCnt = FromPtColl.PointCount;

                IPoint[] controlFromPoints = new IPoint[ControlPtCnt];
                IPoint[] controlToPoints = new IPoint[ControlPtCnt];

                for (int i = 0; i < ControlPtCnt; i++)
                {
                    controlFromPoints[i] = FromPtColl.get_Point(i);
                    controlToPoints[i] = ToPtColl.get_Point(i);
                }

                //创建AffineTransformation2D对象
                //必须使用IAffineTransformation2D3GEN
                //因为DefineFromControlPoints在IAffineTransformation2D中使用C-Style Arrays, 该对象在.NET中不可用.
                IAffineTransformation2D3GEN affineTransformation2D = new AffineTransformation2DClass();
                affineTransformation2D.DefineFromControlPoints(ref controlFromPoints, ref controlToPoints);

                //double fromError = 0;
                //double toError = 0;
                //affineTransformation2D.GetRMSError(ref fromError, ref toError);
                //if (fromError > 0.05)
                //{
                //    MessageBox.Show("RMS error is too large; please redigitize control points");
                //}

                ITransform2D pTransform2D = pGeo as ITransform2D;
                pTransform2D.Transform(esriTransformDirection.esriTransformForward, affineTransformation2D as ITransformation);
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 根据图形获取图幅列表
        /// </summary>
        /// <param name="pGeo">图形</param>
        /// <param name="pFeatCls">图幅结合表要素类</param>
        /// <returns>图幅列表</returns>
        private List<TuFu> GetTufusByGeom(IGeometry pGeo, IFeatureClass pFeatCls)
        {
            if (pGeo is IEnvelope)
            {
                IPolygon polygon = GeometryUtility.PolygonByEnvelpe((IEnvelope)pGeo);
                pGeo = polygon as IGeometry;
            }
            List<TuFu> pSheetNums = new List<TuFu>();
            if (pGeo == null || pGeo.IsEmpty)
                return pSheetNums;

            if (pFeatCls == null || pFeatCls.Fields.FindField(m_strTufuNumField) < 0) return null;
            ISpatialFilter pSpatialFilter = new SpatialFilterClass();
            pSpatialFilter.Geometry = pGeo;
            pSpatialFilter.GeometryField = "SHAPE";
            pSpatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
            IFeatureCursor pFeatCur = pFeatCls.Search(pSpatialFilter, false);
            IFeature pFeat = pFeatCur.NextFeature();
            while (pFeat != null)
            {
                TuFu tufu1 = new TuFu();
                tufu1.TuFuName = pFeat.get_Value(pFeat.Fields.FindField(m_strTufuNumField)).ToString();
                tufu1.Geometry = pFeat.ShapeCopy as IPolygon;
                pSheetNums.Add(tufu1);
                pFeat = pFeatCur.NextFeature();
            }
            return pSheetNums;
        }

        /// <summary>
        /// 获取系统安装目录\Data下的图幅结合表要素类
        /// 图幅结合表为shape格式
        /// </summary>
        /// <param name="sIDX">图幅结合表要素类文件名</param>
        /// <returns>图幅结合表要素类</returns>
        private IFeatureClass GetIDXFeatCls(string sIDX)
        {
            IWorkspaceFactory pFactory = new ShapefileWorkspaceFactoryClass();
            DirectoryInfo dir = new DirectoryInfo(Application.StartupPath + "\\Data");
            if (!dir.Exists)
            {
                dir.Create();
            }
            IFeatureWorkspace pWS = pFactory.OpenFromFile(Application.StartupPath + "\\Data", 0) as IFeatureWorkspace;
            IFeatureClass pFeatCls = null;
            try
            {
                pFeatCls = pWS.OpenFeatureClass(sIDX);
            }
            catch (Exception ex)
            {
                logPanel1.ErrLog("未找到" + sIDX + "数据，请先配置！");
            }
            return pFeatCls;
        }

        private void FrmDataTransformation_FormClosed(object sender, FormClosedEventArgs e)
        {
            DataTransformationForm = null;
        }

        //图层全选
        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            bool bChk = checkBox1.Checked ;
            for (int i = 0; i < this.checkedListBox1.Items.Count; i++)
            {
                this.checkedListBox1.SetItemChecked(i, bChk);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            switch (cboType.SelectedIndex)
            {
                case 0:
                case 1:
                    {
                        saveFileExport.Title = "指定目标文件";
                        if (cboType.SelectedIndex == 0)
                        {
                            saveFileExport.Filter = "File Geodatabase (*.gdb)| *.gdb";
                        }
                        else
                        {
                            saveFileExport.Filter = "Personal Geodatabase(*.mdb) | *.mdb";
                        }

                        if (saveFileExport.ShowDialog() == DialogResult.OK)
                        {
                            txtExportPath.ControlText = saveFileExport.FileName.Substring(0, saveFileExport.FileName.Length - 4);
                            //m_pExportType = cboType.SelectedIndex;
                        }
                        break;
                    }
                case 2:
                    {
                        FolderBrowserDialog fbdlg = new FolderBrowserDialog();
                        fbdlg.ShowNewFolderButton = true;
                        fbdlg.Description = "选择导出路径";
                        if (fbdlg.ShowDialog() == DialogResult.OK)
                        {
                            txtExportPath.ControlText = fbdlg.SelectedPath;
                            //m_pExportType = cboType.SelectedIndex;
                        }
                        break;
                    }

                default:
                    {
                        break;
                    }

            }
        }
    }
}
